#ifndef xpack_lang_cxx_split
#define xpack_lang_cxx_split
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::lang_cxx::inc
#include"define/base_type.hpp"
#include"dumb/disable_copy.hpp"
#include"interface/seqptr.hpp"
#include"interface/unified_seq.hpp"
#include"lang/cxx/find.hpp"
#include"lang/cxx.hpp"
#include"macro/xexport.hpp"
#include"macro/xstruct.hpp"
#include"utils/mix_buffer.hpp"
#pragma pop_macro("xuser")

namespace mixc::lang_cxx{
    #define xthe_friend()                                   \
        template<class>                                     \
        friend void split_core(                             \
            auto            const & self,                   \
            auto            const & separator,              \
            uxx                     separator_length,       \
            keep_separator_t        keep_separator,         \
            auto            const & compare,                \
            auto            const & receive                 \
        )

    xstruct(
        xname(cxx_split_item),
        xprif(m_index, uxx),
        xpric(m_length, sizeof(uxx) * 8 - 1, uxx),
        xpric(m_is_separator, 1, uxx)
    )
    public:
        xthe_friend();
    public:
        xprops()
            xpubget(index, uxx);
            xpubget(length, uxx);
            xpubget(is_separator, bool);
        $

        xprops_operator()
    public:
        constexpr cxx_split_item():
            m_index(0),
            m_length(0),
            m_is_separator(0){
        }
    $

    template<class item_t>
    xstruct(
        xtmpl(cxx_split_result, item_t),
        xpubb(inc::disable_copy),
        xprif(m_count_of_separator, uxx),
        xprif(m_buffer, inc::mix_buffer<cxx_split_item> *),
        xprif(m_content, item_t const *)
    )
    public:
        xthe_friend();
    public:
        xprops()
            xpubgetx(count_of_segment, uxx){
                xr{ return (*xthe.m_buffer)->length; }
            };

            xpubget(count_of_separator, uxx);
        $

        xprops_operator()

    private:
        constexpr cxx_split_result(inc::mix_buffer<cxx_split_item> * buffer, item_t const * content):
            m_count_of_separator(0),
            m_buffer(buffer),
            m_content(content){
        }

    public:
        cxx_split_item segment_of(uxx index) const {
            return (*m_buffer)[index];
        }

        inc::cxx<item_t> segment_content_of(uxx index) const {
            auto item = (*m_buffer)[index];
            return { m_content + item->index, item->length };
        }
    $




    template<class item_t>
    inline void split_core(
        auto            const & self,
        auto            const & separator, 
        uxx                     separator_length,
        keep_separator_t        keep_separator,
        auto            const & compare,
        auto            const & receive
    ) {
        using csi               = cxx_split_item;
        using mbi               = inc::mix_buffer<csi>;
        mbi                     buffer;
        csi                     item{};
        cxx_split_result<item_t>info{ & buffer, (item_t *)self };

        if (keep_separator){
            self.find(separator, compare, [&](uxx index){
                if (item.m_length = index - item.m_index; item.m_length != 0){
                    buffer.push(item);
                }

                item.m_index    = index + separator_length;

                // 放到后边
                csi             sepa{};
                sepa.m_is_separator
                                = true;
                sepa.m_index    = index;
                sepa.m_length   = separator_length;
                info.m_count_of_separator++;
                buffer.push(sepa);
            });
        }
        else{
            self.find(separator, compare, [&](uxx index){
                if (item.m_length = index - item.m_index; item.m_length != 0){
                    buffer.push(item);
                }

                item.m_index    = index + separator_length;
            });
        }

        if (item.m_index < self->length){
            item.m_length       = self->length - item.m_index;
            buffer.push(item);
        }

        receive(info);
    }

    #define xheaderx                            \
        template<class item_t>                  \
        template<class item_seq_t, class>       \
        inline void cxx<item_t>

    #define xheader     template<class item_t> inline void cxx<item_t>

    xheaderx::split(item_seq_t const & separator_list, invoke_split_t receive) const {
        return xthe.split(separator_list, not keep_separator, inc::default_compare<item_t>, receive);
    }

    xheaderx::split(item_seq_t const & separator_list, invoke_compare_t compare, invoke_split_t receive) const {
        return xthe.split(separator_list, not keep_separator, compare, receive);
    }

    xheaderx::split(item_seq_t const & separator_list, keep_separator_t keep_separator, invoke_split_t receive) const {
        return xthe.split(separator_list, keep_separator, inc::default_compare<item_t>, receive);
    }

    xheaderx::split(item_seq_t const & separator_list, keep_separator_t keep_separator, invoke_compare_t compare, invoke_split_t receive) const {
        auto list = inc::unified_seq<item_seq_t>(separator_list);
        auto length = uxx(1); // 分隔符的宽度
        return split_core<item_t>(xthe, list, length, keep_separator, compare, receive);
    }

    xheader::split(item_cref_t separator, invoke_split_t receive) const {
        return xthe.split({ separator }, inc::default_compare<item_t>, receive);
    }

    xheader::split(item_cref_t separator, invoke_compare_t compare, invoke_split_t receive) const {
        return xthe.split({ separator }, compare, receive);
    }

    xheader::split(item_cref_t separator, keep_separator_t keep_separator, invoke_split_t receive) const {
        return xthe.split({ separator }, keep_separator, inc::default_compare<item_t>, receive);
    }

    xheader::split(item_cref_t separator, keep_separator_t keep_separator, invoke_compare_t compare, invoke_split_t receive) const {
        return xthe.split({ separator }, keep_separator, compare, receive);
    }

    xheader::split(the_cref_t separator, invoke_split_t receive) const {
        return xthe.split(separator, not keep_separator, inc::default_compare<item_t>, receive);
    }

    xheader::split(the_cref_t separator, invoke_compare_t compare, invoke_split_t receive) const {
        return xthe.split(separator, not keep_separator, compare, receive);
    }

    xheader::split(the_cref_t separator, keep_separator_t keep_separator, invoke_split_t receive) const {
        return xthe.split(separator, keep_separator, inc::default_compare<item_t>, receive);
    }

    xheader::split(the_cref_t separator, keep_separator_t keep_separator, invoke_compare_t compare, invoke_split_t receive) const {
        auto length = uxx(separator->length); // 分隔符的宽度
        return split_core<item_t>(xthe, separator, length, keep_separator, compare, receive);
    }


    #undef  xthe_friend
    #undef  xheaderx
    #undef  xheader
}

namespace mixc::lang_cxx::origin{
    using mixc::lang_cxx::cxx_split_item;
    using mixc::lang_cxx::cxx_split_result;
    using mixc::lang_cxx::keep_separator;

    using c08_split_item    = cxx_split_item;
    using c08_split_result  = cxx_split_result<char>;
    using c16_split_item    = cxx_split_item;
    using c16_split_result  = cxx_split_result<char16_t>;
}

#endif
